package jmpo.cls;
/**
 * В языке Java все объекты происходят от класса Object.
 * Хотя мы явно этого не указываем в определении класса,
 * неявное наследование существует.
 * Класс Object обладает некоторым набором переопределяемых и fianl методов.
 * 
 * Переопределяемые открытые:
 *     boolean equals(Object o)
 *     int hashCode()
 *     String toString()
 * 
 * Переопределяемые protected:
 *     Object clone()
 *     
 * Непереопределяемые:
 *     Class<?> getClass()
 *     void notify()
 *     void wait()
 * 
 * deprecated:
 *     protected void finalize()
 */

/**
 * toString
 */
final class ToStringOverride {
    @Override
    public String toString() {
        return "My String";
    }
}

/**
 * equals
 */
final class EqualsOverride {
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (null == o) return false;
        if (this.getClass() != o.getClass()) return false;
        final var rha = (EqualsOverride)o;
        if (rha.id != id) return false;
        return true;
    }

    EqualsOverride(long id) {
        this.id = id;
    }

    private long id;
}

/**
 * clone
 */
final class CloneOverride implements Cloneable {
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object o = super.clone();
        final var newCloneOverride = (CloneOverride)o;
        newCloneOverride.name = this.name;
        return newCloneOverride;
    }
    
    @Override
    public String toString() {
        return name + ": " + id;
    }

    CloneOverride(String name, long id) {
        this.name = name;
        this.id = id;
    } 

    private String name;
    private long id;
}

public class ObjectMethods {
    private static boolean toStringTest() {
        return new ToStringOverride().toString().equals("My String");
    }

    private static boolean equalsOverrideTest() {
        var e1 = new EqualsOverride(1);
        var e2 = new EqualsOverride(2);
        var e3 = new EqualsOverride(2);
        return 
            e1.equals(null) == false
            && e1.equals(e2) == false
            && e2.equals(e3) == true;
    }

    private static boolean cloneOverrideTest() throws CloneNotSupportedException {
        var c1 = new CloneOverride("c1", 1);
        var c2 = c1.clone();
        return c1.toString().equals(c2.toString()); 
    }

    private static void test(boolean expectedTrue) {
        if(expectedTrue) {
            System.out.println("Ok!");
            return;
        }

        throw new RuntimeException();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        test(toStringTest());
        test(equalsOverrideTest());
        test(cloneOverrideTest());
    }
    
}
